local AddOnName, Env = ...; local ADDON, DT = Env[1], Env[1].development
-- ~~| Libraries |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
local AceConfigRegistry	= LibStub("AceConfigRegistry-3.0")
local DiesalStyle 		= LibStub("DiesalStyle-1.0")
local DiesalGUI 			= LibStub("DiesalGUI-1.0")
local DiesalMenu 			= LibStub('DiesalMenu-1.0')
-- ~~| Lua Upvalues |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
local pairs, ipairs							= pairs,ipairs
local type	 									= type
local sub, find, format 					= string.sub, string.find, string.format
local floor, ceil, min, max				= math.floor, math.ceil, math.min, math.max
-- ~~| WoW Upvalues |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
local GetTime  								= GetTime
-- ~~| ActionLog |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

-- ~~| ActionLog StyleSheets |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
local windowStyleSheet = {
	['frame-background'] = {
		type			= 'texture',
		layer			= 'BACKGROUND',
		color			= '080808',
		offset		= 0,
	},
	['frame-shadow'] = {
		type			= 'shadow',
	},
	['frame-outline'] = {
		type			= 'outline',
		layer			= 'BORDER',
		color			= '000000',
		offset		= 0,
	},
	['frame-inline'] = {
		type			= 'outline',
		layer			= 'BORDER',
		color			= '000000',
		offset		= {-2,-2,-17,-2},
	},
	['titleBar-background'] = {
		type			= 'texture',
		layer			= 'BACKGROUND',
		gradient		= 'VERTICAL',
		color			= 'FFFFFF',
		alpha			= .01,
		alphaEnd		= .02,
		offset 		= -1,
	},
	['titleBar-outline'] = {
		type			= 'outline',
		layer			= 'ARTWORK',
		gradient		= 'VERTICAL',
		color			= 'FFFFFF',
		alpha			= .01,
		alphaEnd		= .03,
		offset		= -1,
	},
	['titletext-Font'] = {
		type			= 'font',
		color			= 'd8d8d8',
	},
	['closeButton-icon'] = {
		type			= 'texture',
		layer			= 'ARTWORK',
		texFile		= 'DiesalGUIcons',
		texCoord		= {9,5,16,256,128},
		alpha 		= .4,
		offset		= {-2,nil,-2,nil},
		width			= 16,
		height		= 16,
	},
	['closeButton-iconHover'] = {
		type			= 'texture',
		layer			= 'HIGHLIGHT',
		texFile		= 'DiesalGUIcons',
		texCoord		= {9,5,16,256,128},
		texColor		= 'b30000',
		alpha			= 1,
		offset		= {-2,nil,-2,nil},
		width			= 16,
		height		= 16,
	},
	['header-background'] = {
		type			= 'texture',
		layer			= 'BACKGROUND',
		color			= '000000',
	},
	['header-outline'] = {
		type			= 'outline',
		layer			= 'BORDER',
		color			= '000000',
		offset		= 1,
	},	
	['content-background'] = {		
		type			= 'texture',
		layer			= 'BACKGROUND',
		color			= '0e0e0e',
		offset		= {0,0,-1,0},
	},
	['content-outline'] = {		
		type			= 'outline',
		layer			= 'BORDER',
		color			= 'FFFFFF',		
		alpha			= .03,
		offset		= {0,0,-1,0},
	},
	['footer-background'] = {			
		type			= 'texture',
		layer			= 'BACKGROUND',
		gradient		= 'VERTICAL',						
		color			= '232323',
		colorEnd		= '272727',
		offset 		= {0,0,-1,0},		
	},	
	['footer-outline'] = {			
		type			= 'outline',
		layer			= 'BORDER',
		color			= 'FFFFFF',
		gradient		= 'VERTICAL',
		alpha			= .02,
		alphaEnd		= .05,
		offset		= {0,0,-1,0},		
	},	
	['footer-divider'] = {			
		type			= 'texture',
		layer			= 'BACKGROUND',		
		color			= '040404',	
		offset		= {0,0,0,nil},	
		height		= 1,	
	},			
}
local styleSheet = {
	['headerCount-background'] = {
		type			= 'texture',
		layer			= 'BACKGROUND',
		gradient		= 'VERTICAL',
		color			= 'FFFFFF',
		alpha			= .15,
		alphaEnd		= .25,		
	},
	['headerCount-outline'] = {
		type			= 'outline',
		layer			= 'BORDER',
		gradient		= 'VERTICAL',	
		color			= 'ffffff',
		alpha 		= .03,
		alphaEnd		= .07,		
	},	
	['headerSpell-background'] = {
		type			= 'texture',
		layer			= 'BACKGROUND',
		gradient		= 'VERTICAL',
		color			= 'FFFFFF',
		alpha			= .15,
		alphaEnd		= .25,				
	},
	['headerSpell-outline'] = {
		type			= 'outline',
		layer			= 'BORDER',
		gradient		= 'VERTICAL',	
		color			= 'ffffff',
		alpha 		= .03,
		alphaEnd		= .07,		
	},
	['headerAction-background'] = {
		type			= 'texture',
		layer			= 'BACKGROUND',
		gradient		= 'VERTICAL',
		color			= 'FFFFFF',
		alpha			= .15,
		alphaEnd		= .25,			
	},
	['headerAction-outline'] = {
		type			= 'outline',
		layer			= 'BORDER',
		gradient		= 'VERTICAL',	
		color			= 'ffffff',
		alpha 		= .03,
		alphaEnd		= .07,		
	},
	['headerID-background'] = {
		type			= 'texture',
		layer			= 'BACKGROUND',
		gradient		= 'VERTICAL',
		color			= 'FFFFFF',
		alpha			= .15,
		alphaEnd		= .25,			
	},
	['headerID-outline'] = {
		type			= 'outline',
		layer			= 'BORDER',
		gradient		= 'VERTICAL',	
		color			= 'ffffff',
		alpha 		= .03,
		alphaEnd		= .07,			
	},
	['headerTime-background'] = {
		type			= 'texture',
		layer			= 'BACKGROUND',
		gradient		= 'VERTICAL',
		color			= 'FFFFFF',
		alpha			= .15,
		alphaEnd		= .25,			
	},
	['headerTime-outline'] = {
		type			= 'outline',
		layer			= 'BORDER',
		gradient		= 'VERTICAL',	
		color			= 'ffffff',
		alpha 		= .03,
		alphaEnd		= .07,		
	},	
}

local clearButtonStyle = {
	type			= 'texture',
	texFile		='DiesalGUIcons',
	texCoord		= {13,5,16,256,128},
	alpha 		= .7,	
	offset		= {-2,nil,-2,nil},
	width			= 16,
	height		= 16,			
}
local clearButtonNormal = {
	type			= 'texture',	
	alpha 		= .7,			
}
local clearButtonOver = {
	type			= 'texture',	
	alpha 		= 1,		
} 
-- ~~| ActionLog Locals |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
local GREY75		= ADDON:GetTxtColor('c0c0c0')
local GREY50		= ADDON:GetTxtColor('808080')
local BLUE			= ADDON:GetTxtColor('0099e6')	
local ORANGE		= ADDON:GetTxtColor('e6c000') 
local PURPLE		= ADDON:GetTxtColor('9900e5') 
local RED			= ADDON:GetTxtColor('ff0000') 
local YELLOW		= ADDON:GetTxtColor('ffff00')
local filteredLog = {}

local lastRefreshTime = 0
local refreshThrottle = CreateFrame('Frame')
refreshThrottle:Hide()
function refreshThrottle:Check()
	if lastRefreshTime >= GetTime() then			
		self.throttle = .05
		self:Show()
	return true	end
	lastRefreshTime = GetTime() 	
end
refreshThrottle:SetScript('OnUpdate', function(this,elapsed)
	if this.throttle < 0 then
		ADDON.ActionLog:RefreshLog()			
	else		
		this.throttle = this.throttle - elapsed			
	end	
end)
-- ~~| ActionLog Methods |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
local methods = {
	['SetSettings'] = function(self,settings,update)
		for key,value in pairs(settings) do
			self.settings[key] = value
		end
		if update then self:Update()	end
	end,
	['Update'] = function(self)
		local db			= self.db
		local frame		= self.frame

		frame:ClearAllPoints()
		frame[db.show and "Show" or "Hide"](frame)
		if db.top and db.left then
			frame:SetPoint("TOP",UIParent,"BOTTOM",0,db.top)
			frame:SetPoint("LEFT",UIParent,"LEFT",db.left,0)
		else
			frame:SetPoint("CENTER",UIParent,"CENTER")
		end
		frame:SetWidth(db.width)
		frame:SetHeight(db.height)
		
		self.succCheck:SetChecked(db.succFilter)
		self.sentCheck:SetChecked(db.sentFilter)
	end,
	['UpdateTooltip'] = function(self)

	end,
	['Show'] = function(self)
		self.frame:Show()
	end,
	['Hide'] = function(self)
		self.frame:Hide()
	end,	
	['SetSpellColWidth'] = function(self,width)		
		self.headerSpell:SetWidth(width)		
		self.settings.spellColWidth = width
		local rows = self.settings.rows
		for i = 1, #rows do
			rows[i].rowSpell:SetWidth(width)				
		end
	end,	
	['SetRows'] = function(self,newCount)
		local rows = self.settings.rows
		local oldCount = #rows
		
		if newCount < oldCount then -- remove rows  
			for i = oldCount, newCount + 1, -1 do
				DiesalGUI:Release(rows[i])
				rows[i] = nil				
			end												
		elseif newCount > oldCount then -- Get Rows
			for i = oldCount + 1, newCount do 
				local row = DiesalGUI:Create('ActionLogRow')	
				rows[#rows+1] = row				
				row:SetParentObject(self.window)
				row:SetSettings({
					spellColWidth	= self.settings.spellColWidth,				
					rowHeight		= self.settings.rowHeight,
					rows				= rows,								
					position			= i,												
				},true)
			end			
		end
		self:RefreshLog()
	end,	
	['RefreshLog'] = function(self)
		refreshThrottle:Hide()
		if not self.frame:IsVisible() then return end
		if not next(ADDON.RotationEngine.actionLog) then for i = 1, #self.settings.rows do self.settings.rows[i]:ClearAction() end return end		
			
		-- throttle refresh
		if refreshThrottle:Check() then return end			
		
		wipe(filteredLog)
		
		local rows			= self.settings.rows			
		local log 			= ADDON.RotationEngine.actionLog		
		local succFilter 	= self.db.succFilter
		local sentFilter 	= self.db.sentFilter		
		
		for i = 1, #log do
			if not sentFilter or log[i].action ~= 'SPELLCAST_SENT' then 
				if not succFilter or log[i].action ~= 'SPELLCAST_SUCCEEDED' then
					if log[i].action then filteredLog[#filteredLog + 1] = log[i] end
				end
			end 
		end
		
		local logFrom = #filteredLog - #rows
		logFrom = logFrom > 0 and logFrom or 0
		
		for i = 1, #rows do
			if filteredLog[i] then				
				rows[i]:SetAction(filteredLog[i+logFrom])
			else
				rows[i]:ClearAction()				
			end
		end				
	end,
	['ClearLog'] = function(self)
		wipe(ADDON.RotationEngine.actionLog)
		self:RefreshLog()
	end,		
}
-- ~~| ActionLog Constructor |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
function ADDON:constructActionLog()
	local self = {}
	self.db = ADDON.db.profile.actionLog
	-- ~~ Default Settings ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	local settings = {
		rows 			= {},
		numRows		= 10,
		rowHeight	= 18,		
	}
	self.settings = settings
	-- ~~ Construct ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	local window = DiesalGUI:Create('Window')
	window:ReleaseTextures()
	window:AddStyleSheet(windowStyleSheet)
	window:SetSettings({
		header			= true,
		footer			= true,
		headerHeight	= 18,
		minWidth 		= 420,
		minHeight 		= 218,
		height			= self.db.height,
		width				= self.db.width,
		sizerR			= false,
		sizerB			= true,
		sizerHeight		= 20,
		sizerBRHeight	= 20,
		sizerBRWidth	= 20,
	},true)
	window:SetTitle(RED..AddOnName,GREY75..'Action Log')	
	window.sizerBR:SetPoint("BOTTOMRIGHT",window.frame,"BOTTOMRIGHT",0,0)
	window.sizerBR:SetFrameLevel(100)
	window:SetEventListener('OnSizeChanged', function(this,event,width,height)
		
		self:SetRows(floor((this.content:GetHeight()+1)*.0555556))	-- * .0555556 == /18	
		self:SetSpellColWidth(ADDON:Round((width-100) * .3))		
	end)
	window:SetEventListener('OnSizeStop', function(this,event,width,height)		
		
		local windowHeight	= height - this.content:GetHeight() 	
		height = (#self.settings.rows*18) + windowHeight
				
		window.frame:SetHeight(height)		
		self.db.width 	= width
		self.db.height = height		
	end)	
	window:SetEventListener('OnDragStop', function(this,event,left,top)
		self.db.left 	= left
		self.db.top 	= top					
	end)
	window:SetEventListener('OnClose', function(this,event)
		self.db.show = false
		AceConfigRegistry:NotifyChange(AddOnName)								
	end)
	window:SetEventListener('OnShow', function(this,event)		
		self:RefreshLog()			
	end)	

	local headerCount		= CreateFrame('Frame',nil,window.header)	
	local headerSpell 	= CreateFrame('Frame',nil,window.header)	
	local headerAction	= CreateFrame('Frame',nil,window.header)
	local headerID 		= CreateFrame('Frame',nil,window.header)	
	local headerTime 		= CreateFrame('Frame',nil,window.header)
	
	headerCount:SetPoint('TOPLEFT')
	headerCount:SetPoint('BOTTOMLEFT')
	headerCount:SetWidth(settings.rowHeight-1)
	local headerCountText = headerCount:CreateFontString(nil)
	headerCountText:SetHeight(1)
	headerCountText:SetPoint('TOPLEFT',6,-9)	
	headerCountText:SetJustifyH("LEFT")
	headerCountText:SetFont(DiesalFontNormal:GetFont())
	headerCountText:SetText(GREY75.."#")	
	
	headerSpell:SetPoint('TOPLEFT',headerCount,'TOPRIGHT',1,0)
	headerSpell:SetPoint('BOTTOMLEFT',headerCount,'BOTTOMRIGHT',1,0)
	local headerSpellText = headerSpell:CreateFontString(nil)
	headerSpellText:SetHeight(1)
	headerSpellText:SetPoint('TOPLEFT',5,-9)
	headerSpellText:SetJustifyH("TOP")	
	headerSpellText:SetJustifyH("LEFT")	
	headerSpellText:SetFont(DiesalFontNormal:GetFont())
	headerSpellText:SetText(GREY75.."Spell")	
	
	headerAction:SetPoint('TOPLEFT',headerSpell,'TOPRIGHT',1,0)
	headerAction:SetPoint('BOTTOMRIGHT',headerID,'BOTTOMLEFT',-1,0)
	local headerActionText = headerAction:CreateFontString(nil)
	headerActionText:SetPoint('TOPLEFT',5,-4)	
	headerActionText:SetJustifyH("LEFT")	
	headerActionText:SetFont(DiesalFontNormal:GetFont())
	headerActionText:SetText(GREY75.."Action")			
	
	headerID:SetPoint('TOPRIGHT',headerTime,'TOPLEFT',-1,0)
	headerID:SetPoint('BOTTOMRIGHT',headerTime,'BOTTOMLEFT',-1,0)	
	headerID:SetWidth(41) 
	local headerIDText = headerID:CreateFontString(nil)
	headerIDText:SetPoint('TOPLEFT',5,-4)	
	headerIDText:SetJustifyH("LEFT")	
	headerIDText:SetFont(DiesalFontNormal:GetFont())
	headerIDText:SetText(GREY75.."LineID")	
	
	headerTime:SetPoint('TOPRIGHT')
	headerTime:SetPoint('BOTTOMRIGHT')
	headerTime:SetWidth(63) 
	local headerTimeText = headerTime:CreateFontString(nil)
	headerTimeText:SetPoint('TOPLEFT',5,-4)	
	headerTimeText:SetJustifyH("LEFT")	
	headerTimeText:SetFont(DiesalFontNormal:GetFont())
	headerTimeText:SetText(GREY75.."Time")	
	
	local filterText = window.footer:CreateFontString(nil)
	filterText:SetHeight(1)
	filterText:SetPoint('TOPLEFT',5,-11)
	filterText:SetJustifyH("TOP")	
	filterText:SetJustifyH("LEFT")	
	filterText:SetFont(DiesalFontNormal:GetFont())
	filterText:SetText(GREY75.."Filter:       Spellcast Sent       Spellcast Succeeded")	
	
	local clearButton = DiesalGUI:Create('Button')
	clearButton:SetParent(window.footer)
	clearButton:SetPoint('TOPLEFT',250,-1)	
	clearButton:SetSettings({		
		width			= 20,		
		height		= 20,
	},true)
	clearButton:SetStyle('frame',clearButtonStyle)	
	clearButton:SetEventListener('OnEnter', 	function()
		GameTooltip:SetOwner(clearButton.frame, "ANCHOR_TOPRIGHT",0,2)				
		GameTooltip:AddLine(BLUE..'Clear Action Log')
		GameTooltip:Show()				 
		clearButton:SetStyle('frame',clearButtonOver)		
	end)		
	clearButton:SetEventListener('OnLeave', 	function()		
		clearButton:SetStyle('frame',clearButtonNormal)
		GameTooltip:Hide()
	end)
	clearButton:SetEventListener('OnClick',	function() self:ClearLog() end)	
	
	local sentCheck = DiesalGUI:Create('CheckBox')
	sentCheck:SetParent(window.footer)	
	sentCheck:SetPoint("TOPLEFT",43,-5)		
	sentCheck:SetEventListener('OnValueChanged', function(this,event,value)
		self.db.sentFilter = value
		self:RefreshLog()				
	end)	
			
	local succCheck = DiesalGUI:Create('CheckBox')
	succCheck:SetParent(window.footer)	
	succCheck:SetPoint("TOPLEFT",133,-5)	
	succCheck:SetEventListener('OnValueChanged', function(this,event,value)			
		self.db.succFilter = value
		self:RefreshLog()				
	end)
	
	

		
	-- ~~ Frames ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	self.window 				= window
	self.frame 					= window.frame

	self.headerCount 			= headerCount
	self.headerSpell 			= headerSpell
	self.headerAction 		= headerAction
	self.headerID 			= headerID
	self.headerTime 			= headerTime
	
	self.succCheck				= succCheck
	self.sentCheck				= sentCheck
	-- ~~ Methods ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	for method, func in pairs(methods) do
		self[method] = func
	end
	-- ~~ Style ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	self.textures = {}
	DiesalStyle:AddObjectStyleSheet(self,styleSheet)
	-- ~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~	
	self:Hide()
	return self
end